﻿using AspectCore.DynamicProxy;
using AspectCore.Extensions.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
using NetMicro.Core.ApiFunction;
using NetMicro.Core.Extensions;
using NetMicro.HttpClient.Exceptions;
using NetMicro.HttpClient.Extensions;
using NetMicro.HttpClient.Internal;

namespace NetMicro.HttpClient.AspectExtend
{
    /// <summary>
    /// 服务发现动态拦截
    /// </summary>
    public class HttpServiceBusProxy : IInterceptor
    {

        /// <summary>
        /// 
        /// </summary>
        public bool AllowMultiple { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public bool Inherited { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int Order { get; set; }


        /// <summary>
        /// 动态拦截
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task Invoke(AspectContext context, AspectDelegate next)
        {
            try
            {
                HttpClientPart httpclientPart = context.ServiceMethod.BuildServiceBusHttpClientPart(context.Parameters);
                if (context.ServiceMethod.ReturnType.GetTypeInfo().IsTask())
                {
                    await httpclientPart.SendAsync();
                    context.ReturnValue = Task.CompletedTask;
                    return;
                }
                if (context.ServiceMethod.ReturnType.IsVoid())
                {
                    await httpclientPart.SendAsync();
                    return;
                }

                MethodInfo methodInfo = typeof(HttpClientPart).GetMethod("SendAsAsync", BindingFlags.Instance | BindingFlags.Public);
                if (!context.ServiceMethod.IsAsync())
                {
                    Type resultTypeSync = context.ServiceMethod.ReturnType;
                    MethodInfo miSync = methodInfo.MakeGenericMethod(new Type[] { resultTypeSync });
                    Task task = miSync.Invoke(httpclientPart, new object[] { default }) as Task;
                    await task.ConfigureAwait(false);
                    PropertyInfo resultProperty = task.GetType().GetProperty("Result");
                    context.ReturnValue = resultProperty.GetValue(task);
                    return;
                }
                Type resultTypeAsync = context.ServiceMethod.ReturnType.GetGenericArguments()[0];
                MethodInfo miAsync = methodInfo.MakeGenericMethod(new Type[] { resultTypeAsync });
                context.ReturnValue = miAsync.Invoke(httpclientPart, new object[] { default });
            }
            catch (HttpClientException ex)
            {
                context.ServiceProvider.GetService<ILogger<HttpServiceBusProxy>>().LogError(ex, "远程调用发生异常");
                if (context.ServiceMethod.ReturnType.IsVoid() || context.ServiceMethod.ReturnType.GetTypeInfo().IsTask())
                    throw;
                string error_value = ServiceResult.Faild(ex.Code, ex.Message).ToJson();
                if (!context.ServiceMethod.IsAsync())
                {
                    context.ReturnValue = JsonConvert.DeserializeObject(error_value, context.ServiceMethod.ReturnType);
                    return;
                }
                Type resultTypeAsync = context.ServiceMethod.ReturnType.GetGenericArguments()[0];
                MethodInfo methodInfo = typeof(HttpServiceBusProxy).GetMethod("HandleAsync", BindingFlags.Instance | BindingFlags.Public);
                MethodInfo mi = methodInfo.MakeGenericMethod(resultTypeAsync);
                context.ReturnValue = mi.Invoke(this, new[] { JsonConvert.DeserializeObject(error_value, resultTypeAsync) });
            }
            catch (Exception ex)
            {
                context.ServiceProvider.GetService<ILogger<HttpServiceBusProxy>>().LogError(ex, "远程调用发生异常");
                if (context.ServiceMethod.ReturnType.IsVoid() || context.ServiceMethod.ReturnType.GetTypeInfo().IsTask())
                    throw;
                string error_value = ServiceResult.Faild(HttpStatusCode.InternalServerError, ex.Message).ToJson();
                if (!context.ServiceMethod.IsAsync())
                {
                    context.ReturnValue = JsonConvert.DeserializeObject(error_value, context.ServiceMethod.ReturnType);
                    return;
                }
                Type resultTypeAsync = context.ServiceMethod.ReturnType.GetGenericArguments()[0];
                MethodInfo methodInfo = typeof(HttpServiceBusProxy).GetMethod("HandleAsync", BindingFlags.Instance | BindingFlags.Public);
                MethodInfo mi = methodInfo.MakeGenericMethod(resultTypeAsync);
                context.ReturnValue = mi.Invoke(this, new[] { JsonConvert.DeserializeObject(error_value, resultTypeAsync) });
            }
        }


        /// <summary>
        /// 异步返回值转换
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public Task<T> HandleAsync<T>(T value)
        {
            return Task.FromResult(value);
        }




    }
}
